﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;

namespace HttpLib.Util
{
    public class SignExtension
    {
        public static bool Validate(string timeStamp, string nonce, int staffId, string data, string signature)
        {
            var hash = System.Security.Cryptography.MD5.Create();
            //拼接签名数据
            var signStr = timeStamp + nonce + staffId + data;
            //将字符串中字符按升序排序
            var sortStr = string.Concat(signStr.OrderBy(c => c));
            var bytes = Encoding.UTF8.GetBytes(sortStr);
            //使用MD5加密
            var md5Val = hash.ComputeHash(bytes);
            //把二进制转化为大写的十六进制
            StringBuilder result = new StringBuilder();
            foreach (var c in md5Val)
            {
                result.Append(c.ToString("X2"));
            }

            return result.ToString().ToUpper() == signature;
        }

        #region OpenId签名及验证
        /// <summary>
        /// 生成Code
        /// </summary>
        /// <param name="openId">openid</param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string MakeCode(string openId, string key)
        {
            DateTime time = DateTime.Now;
            string data = time.ToString("dd") + openId  + time.ToString("yyyy") + key + time.ToString("MM");
            MD5 md5 = MD5.Create();
            StringBuilder result = new StringBuilder();
            byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(data));
            for (int i = 0; i < s.Length; i++)
            {
                string btos = s[i].ToString("X2");
                result.Append(btos);
            }
            return result.ToString();
        }
        /// <summary>
        /// Code验证
        /// </summary>
        /// <param name="openid">openid</param>
        /// <param name="code">待验证的数据</param>
        /// <param name="key">自己系统规定的key</param>
        /// <returns></returns>
        public static bool ValidateCode(string openid, string code, string key)
        {
            string signedData = MakeCode(openid, key);
            return code.Equals(signedData, StringComparison.OrdinalIgnoreCase);
        }
        #endregion

        #region 请求签名
        /// <summary>
        /// 给请求签名
        /// </summary>
        /// <param name="parameters">所有字符型的请求参数</param>
        /// <param name="secret">签名密钥</param>
        /// <param name="qhs">是否前后都加密进行签名</param>
        /// <returns></returns>
        public static string SignRequest(IDictionary<string, string> parameters, string secret, bool qhs)
        {
            //第一步：把字典按Key的字母顺序排序
            IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters);
            IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator();
            //第二步：把所有参数名和参数值串在一起
            StringBuilder query = new StringBuilder(secret);
            while (dem.MoveNext())
            {
                string key = dem.Current.Key;
                string value = dem.Current.Value;
                if (!string.IsNullOrWhiteSpace(key))
                {
                    query.Append(key).Append(value);
                }
            }
            if (qhs)
            {
                query.Append(secret);
            }
            // 第三部：使用md5运算
            string md5Str = query.ToString();
            MD5 md5 = MD5.Create();
            byte[] bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(md5Str));
            // 第四部：把二进制转为大写的十六进制
            StringBuilder result = new StringBuilder();
            for (int i = 0; i < bytes.Length; i++)
            {
                result.Append(bytes[i].ToString("x").PadLeft(2, '0'));
            }
            return result.ToString();
        }
        /// <summary>
        /// 验证签名
        /// </summary>
        /// <param name="parameters">所有字符型的请求参数</param>
        /// <param name="signature">签名的字符串</param>
        /// <param name="secret">加密字符串</param>
        /// <param name="qhs">是否前后都加密进行签名</param>
        /// <returns></returns>
        public static bool ValidateSign(IDictionary<string, string> parameters, string signature, string secret, bool qhs)
        {
            string currentSinnature =  SignRequest(parameters, secret, qhs);
            return string.Equals(currentSinnature, signature);
        }
        /// <summary>
        /// 获取时间戳(秒)
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public static long DateTimeToJsTimeStamp(DateTime dateTime)
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds);
        }
        #endregion
    }
}
